﻿using Imaginecup.Recycling.Behavior;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Imaginecup.Recycling.Object;
using Imaginecup.shareData;
using Imaginecup.Recycling.GameMan;
using Imaginecup.recycling.Behavior;
using Imaginecup.recycling.Sprite;
using Imaginecup.recycling.Object.Entity;
using System.Collections.Generic;
using Imaginecup.Engine;
using Imaginecup.util;
using Microsoft.Xna.Framework.Input;
using Imaginecup.util.StaticValue;
using System;
using Imaginecup.gameState.recycling.Object;
using Imaginecup.gameState.recycling.Observable;

namespace Imaginecup.recycling.Object
{
    [Flags]
    public enum CharacterState
    {
        Idle = 0,
        Running = 1,
        Jump = 2,
        Sliding = 4,
        Pet_None,
        Pet_Eat
    }

    public class Player : GameObject, IPlayer
    {
        private CharacterState m_CurrentAniKey;
        private Dictionary<CharacterState, IAnimationBehavior> m_Animation;
        private float m_CurrentTime;
        private float m_DelayTime = 0.05f;

        private bool m_bOnGround = true;
        private Vector2 fallSpeed = new Vector2(0, 20);
        private Pet m_PetCharacter;

        private float PlayerSpeed
        {
            get { return StaticValues.Speed; }
        }

        public Player()
        {
            m_TextureName = "Hero_Run";
            m_Direction = Direction.Left;
        }

        public void ChangeTexture(string textureName)
        {
            m_TextureName = textureName;
        }

        protected override void Initialize()
        {
            m_Info = new ObjectInfo(new Rectangle(200, 100, 96, 96));
            m_Info.CollisionRectangle = new Rectangle(24, 0, 48, 96);
            
            m_Animation = new Dictionary<CharacterState, IAnimationBehavior>();

            AnimationBehavior runAni = new AnimationBehavior(ResourceManager.GetInstance().GetContent("Hero_Run"), 96);
            runAni.CurrentCharacterState = CharacterState.Running;
            runAni.NextCharacterState = CharacterState.Running;
            m_Animation.Add(CharacterState.Running, runAni);

            AnimationBehavior jumpAni = new AnimationBehavior(ResourceManager.GetInstance().GetContent("Hero_Jump"), 96);
            jumpAni.SetLoopAnimationFlag(false);
            jumpAni.CurrentCharacterState = CharacterState.Jump;
            jumpAni.NextCharacterState = CharacterState.Running;
            m_Animation.Add(CharacterState.Jump, jumpAni);

            AnimationBehavior slidingAni = new AnimationBehavior(ResourceManager.GetInstance().GetContent("Hero_Sliding"), 96);
            slidingAni.SetLoopAnimationFlag(false);
            slidingAni.CurrentCharacterState = CharacterState.Sliding;
            slidingAni.NextCharacterState = CharacterState.Running;
            m_Animation.Add(CharacterState.Sliding, slidingAni);

            m_CurrentAniKey = CharacterState.Running;

            m_PetCharacter = new Pet(m_Info.CollisionRectangle);
        }

        public override void Draw(SpriteBatch spriteBatch, GameTime gametime)
        {
            spriteBatch.Begin();
            if ((m_Direction & Direction.None) != 0) // 대기 동작일 경우
            {
                spriteBatch.Draw(ResourceManager.GetInstance().GetContent(m_TextureName), m_Info.WorldLocation, Color.White);
            }
            else // 이동하는 경우
            {
                SpriteEffects effets = new SpriteEffects();

                if ((m_Direction & Direction.Left) != 0)
                    effets = SpriteEffects.None;
                else if ((m_Direction & Direction.Right) != 0)
                    effets = SpriteEffects.FlipHorizontally;

                if (Camera.ObjectIsVisible(m_Info.WorldRectangle))
                {
                    spriteBatch.Draw(
                        m_Animation[m_CurrentAniKey].GetTexture(),
                        Camera.WorldToScreen(m_Info.WorldLocation),
                        m_Animation[m_CurrentAniKey].FrameRectangle,
                        //new Rectangle(0 + StaticValues.PLAYER_SIZE * m_Animation[m_CurrentAniKey].GetFramNumber(), 0, StaticValues.PLAYER_SIZE, StaticValues.PLAYER_SIZE),
                        Color.White,
                        0.0f,
                        Vector2.Zero,
                        1.0f,
                        effets,
                        0.0f);
                }
            }
            m_PetCharacter.Draw(spriteBatch, gametime);
            spriteBatch.End();
        }
#if XBOX
        private void XBOXInput()
        {
            IGamePadHandler gamePad = GamePadHandler.GetInputHandler();
            if (gamePad.IsOneDown(Buttons.DPadDown))
            {
                AnimationChange(CharacterState.Sliding);
            }
            else if (gamePad.IsOneUp(Buttons.DPadDown) && m_CurrentAniKey != CharacterState.Running)
            {
                AnimationChange(CharacterState.Running);
            }
            else if (gamePad.IsOneDown(Buttons.DPadUp))
            {
                AnimationChange(CharacterState.Jump);
                JumpCharacter();
            }
            else if (gamePad.IsOneUp(Buttons.DPadUp) && m_CurrentAniKey != CharacterState.Running)
            {
                AnimationChange(CharacterState.Running);
            }
        }
#endif
#if WINDOWS 
        private void WindowsKeyboradInput()
        {

            IKeyboardInputHandler keyboard = KeyboardInputHandler.GetInputHandler();

            if (keyboard.CurrentKeyboardState.IsKeyDown(Keys.X) && m_bOnGround && m_CurrentAniKey != CharacterState.Sliding)
            {
                AnimationChange(CharacterState.Sliding);
                m_Info.CollisionRectangle = new Rectangle(24, 48, 48, 48);
            }
            else if (keyboard.IsOneKeyUp(Keys.X) && m_CurrentAniKey != CharacterState.Running)
            {
                AnimationChange(CharacterState.Running);
                m_Info.CollisionRectangle = new Rectangle(24, 0, 48, 96);
            }
            if (keyboard.IsOneKeyDown(Keys.C) && m_bOnGround)
            {
                JumpCharacter();
                AnimationChange(CharacterState.Jump);
            }
            else if (keyboard.IsOneKeyUp(Keys.C) && m_CurrentAniKey != CharacterState.Running)
            {
                AnimationChange(CharacterState.Running);
            }
        }
#endif
        public override void Update(GameTime gameTime)
        {
            // 중력적용
            m_Velocity += fallSpeed;
            //카메라를 이동 확인
            RepositionCamera();
#if WINDOWS 
            //키보드 입력처리
            WindowsKeyboradInput();
#endif
#if XBOX
            //키보드 입력처리
            XBOXInput();
#endif
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            m_CurrentTime += elapsed;

            if (m_CurrentTime >= m_DelayTime)
            {
                m_CurrentTime = m_CurrentTime - m_DelayTime;
                UpdateAnimation(gameTime);
            }

            m_Velocity = new Vector2(PlayerSpeed, m_Velocity.Y);

            if (m_Velocity.Y != 0)
            {
                m_bOnGround = false;
            }

            Vector2 moveAmount = m_Velocity * elapsed;

            //가로 세로 충돌 처리 부분 삽입
            moveAmount = HorizontalCollision(moveAmount);
            moveAmount = VerticalCollision(moveAmount);

            Vector2 newPosition = m_Info.WorldLocation + moveAmount;

            newPosition = new Vector2(
                            MathHelper.Clamp(newPosition.X, 0, Camera.WorldRectangle.Width - m_Info.FrameWidth),
                            MathHelper.Clamp(newPosition.Y, 2 * (-TileMap.TileHeight), Camera.WorldRectangle.Height - m_Info.FrameHeight));

            m_Info.WorldLocation = newPosition;

            // 펫의 위치 업데이트
            m_PetCharacter.SetPetByPlayer(m_Info.WorldLocation);
            m_PetCharacter.Update(gameTime);

            // 필요 없어지면 제거
            //m_Info.WorldLocation += moveAmount;

            //PlayerMove(gameTime);
            //ClampToWorld();
        }
        
        // 애니메이션 업데이트 부분
        private void UpdateAnimation(GameTime gameTime)
        {
            if (m_Animation.ContainsKey(m_CurrentAniKey))
            {
                if (m_Animation[m_CurrentAniKey].GetFinishFlag() && !(m_CurrentAniKey == CharacterState.Sliding))
                {
                    AnimationChange(m_Animation[m_CurrentAniKey].GetNextAnimationKey());
                }
                else
                {
                    m_Animation[m_CurrentAniKey].UpdateAnimation(gameTime);
                }
            }
        }

        public void JumpCharacter()
        {
            if(m_bOnGround)
#if !WINDOWS_PHONE
                m_Velocity.Y = -500;
#endif
                m_Velocity.Y = -370;
        }

        public void AnimationChange(CharacterState nextKey)
        {
            m_CurrentAniKey = nextKey;
            m_Animation[m_CurrentAniKey].ResetAnimation();
        }

        public bool IsAnimationPlay()
        {
            if (m_CurrentAniKey == CharacterState.Running)
            {
                return true;
            }
            return false;
        }


        #region 이동 제한이나 플레이어의 충돌관련
        private void ClampToWorld()
        {
            float currentX = m_Info.WorldLocation.X;
            float currentY = m_Info.WorldLocation.Y;

            currentX = MathHelper.Clamp(
                currentX,
                0,
                Camera.WorldRectangle.Right - m_Info.FrameWidth - 34);

            currentY = MathHelper.Clamp(
                currentY,
                0,
                Camera.WorldRectangle.Bottom - m_Info.FrameHeight - 34);

            m_Info.WorldLocation = new Vector2(currentX, currentY);
        }

        private void RepositionCamera()
        {
            int screenLocX = (int)Camera.WorldToScreen(m_Info.WorldLocation).X;

            if (screenLocX > 300)
            {
                Camera.Move(new Vector2(screenLocX - 300, 0));
            }

            if (screenLocX < 50)
            {
                Camera.Move(new Vector2(screenLocX - 50, 0));
            }
        }
   
        //충돌 처리
        private Vector2 HorizontalCollision(Vector2 moveAmount)
        {
            if (moveAmount.X == 0)
                return moveAmount;

            Rectangle afterMoveRect = m_Info.CollisionRectangle;
            afterMoveRect.Offset((int)moveAmount.X, 0);
            Vector2 corner1, corner2, corner3, corner4;

            if (moveAmount.X < 0)
            {
                corner1 = new Vector2(afterMoveRect.Left, afterMoveRect.Top + 1);
                corner2 = new Vector2(afterMoveRect.Left, afterMoveRect.Bottom - 1);
                corner3 = new Vector2(afterMoveRect.Right, afterMoveRect.Top + 1);
                corner4 = new Vector2(afterMoveRect.Right, afterMoveRect.Bottom - 1);
            }
            else
            {
                corner1 = new Vector2(afterMoveRect.Right, afterMoveRect.Top + 1);
                corner2 = new Vector2(afterMoveRect.Right, afterMoveRect.Bottom - 1);
                corner3 = new Vector2(afterMoveRect.Left, afterMoveRect.Top + 1);
                corner4 = new Vector2(afterMoveRect.Left, afterMoveRect.Bottom - 1);
            }

            if (TileMap.IsWallTileByPixel(corner1) || TileMap.IsWallTileByPixel(corner2) || TileMap.IsWallTileByPixel(corner3) || TileMap.IsWallTileByPixel(corner4))
            {
                moveAmount.X = 0;
                m_Velocity.X = 0;
            }

            return moveAmount;
        }
        private Vector2 VerticalCollision(Vector2 moveAmount)
        {
            if (moveAmount.Y == 0)
                return moveAmount;

            Rectangle afterMoveRect = m_Info.CollisionRectangle;
            afterMoveRect.Offset((int)moveAmount.X, (int)moveAmount.Y);
            Vector2 corner1, corner2, corner3, corner4;
            if(moveAmount.Y < 0)
            {
                corner1 = new Vector2(afterMoveRect.Left + 1, afterMoveRect.Top);
                corner2 = new Vector2(afterMoveRect.Right - 1, afterMoveRect.Top);
                corner3 = new Vector2(afterMoveRect.Left + 1, afterMoveRect.Bottom);
                corner4 = new Vector2(afterMoveRect.Right - 1, afterMoveRect.Bottom);
            }
            else
            {
                corner1 = new Vector2(afterMoveRect.Left + 1, afterMoveRect.Bottom);
                corner2 = new Vector2(afterMoveRect.Right - 1, afterMoveRect.Bottom);
                corner3 = new Vector2(afterMoveRect.Left + 1, afterMoveRect.Top);
                corner4 = new Vector2(afterMoveRect.Right - 1, afterMoveRect.Top);
            }
            if (TileMap.IsWallTileByPixel(corner1) || TileMap.IsWallTileByPixel(corner2) || TileMap.IsWallTileByPixel(corner3) || TileMap.IsWallTileByPixel(corner4))
            {
                if (moveAmount.Y > 0)
                    m_bOnGround = true;

                moveAmount.Y = 0;
                m_Velocity.Y = 0;
            }
            return moveAmount;
        }
        #endregion
        public bool IsOnGround()
        {
            return m_bOnGround;
        }


        public IMyObserver GetPet()
        {
            return m_PetCharacter;
        }
    }
}